<?php
/**
 * Created by PhpStorm.
 * User: sh01
 * Date: 2017/12/22
 * Time: 14:53
 */

namespace app;


class SocketServer
{
    public function startServe()
    {
        echo "1--start socket server \r\n";
        //当为零，没有程序执行时间限制，一直执行到程序结束
        set_time_limit(0);
        $ip = '127.0.0.1';
        $port = 1935;
        /**
 9  +-------------------------------
1  *    @socket通信整个过程:
1  +-------------------------------
2  *    @socket_create
3  *    @socket_bind
4  *    @socket_listen
5  *    @socket_accept  接收由一个socket传来的信息
6  *    @socket_read
7  *    @socket_write
8  *    @socket_close
9  +--------------------------------
0  */
        //创建并返回一个连接点（二进制数据 resource 可被某些特定驱动函式识别解析并使用。或者可称为一个资源处理器，资源手柄或者你认为比较形象的名字）
        //AF_INET - ipv4(在UNIX中或试图改为localhost 与 AF_UNIX提高性能),SOCK_STREAM - 全双工字节流方式，依赖于操作系统内置实现来决定,SOL_TCP 具体协议格式
        //由参数采取如何连接，决定资源处理器的特征
        if(($sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP)) < 0)
        {
            echo 'error-1--socket_create error: ' . socket_strerror($sock)."\r\n";
        }

        //绑定主机ip与端口到sock对象（内存对象）
        if(($ret = socket_bind($sock,$ip,$port))<0)
        {
            echo 'error-2--socket_bind error: '.socket_strerror($ret)."\r\n";
        }

        //侦听socket连接（将socket处理器放入执行列表。一旦系统触发1935操作会调用socket处理程序）.侦听的意思是当一个方法执行会带动其它方法执行。其它方法是监听者。触发方法是被侦听者
        //设置侦听队列长度为4。一般unix为128。高并发可以设置加大。当一个请求到达服务器时，队列已满则会返回连接拒绝的错误
        //监听不是一个主动的动作，而是一个主动的绑定，被动的执行（执行中包含接收行为）。当一个事物侦听另一个事件，其实是绑定到另一个事件的连带行为，被动地被对方执行而被动接收到消息
        if(($ret = socket_listen($sock,4))<0)
            echo 'error-3--socket_listen error: '.socket_strerror($ret)."\r\n";
        $count = 0;
        echo '2--start socket_accept loop '."\r\n";
        do{
            echo "count : $count \r\n";
            //很明显，全双工方式，需要一个专门用来发送,一个专门用接收，读的要以写的为基础
            //If there are no pending connections, socket_accept() will block until a connection becomes present
            //如果队列中没有即将到来的连接请求，socket_accept() 将会阻塞程序直到下一个连接发起
            if(($msgSock = socket_accept($sock)) < 0)  //阻塞（阻塞机制或者是事件主题的轮循机制？）
            {
                echo 'error-4--socket_accept error: '.socket_strerror($msgSock)."\r\n";
                break;
            }else
            {
                $sendMsg = 'I am from socket server ';
                socket_write($msgSock,$sendMsg,strlen($sendMsg));
                echo "3--socket server write msg [ $sendMsg ] done \r\n";
                $buf = socket_read($msgSock,8192);
                $talkBack = '4--socket server read msg from client: content [ '.$buf." ] \r\n";
                echo $talkBack;

                if(++$count>=20)
                    break;
                echo '5--socket server close msg sock server '."\r\n";
                socket_close($msgSock);
            }
        }while(true);

        echo '6--socket server closed '."\r\n";
        socket_close($sock);
    }
}

//功能测试
$socketServer = new SocketServer();
$socketServer->startServe();